<?php

namespace Commands;

use App\Model\Server\MasterEnum;
use Database\Connection;
use Database\DatabasesProviders;
use Database\Db;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;

class GiiControllerCommand extends Command
{


    use GiiTrait;


    public array $type = [
        'int'    => ['tinyint', 'smallint', 'mediumint', 'int', 'bigint', 'timestamp'],
        'string' => ['char', 'varchar', 'tinytext', 'text', 'mediumtext', 'year', 'longtext', 'date', 'time', 'datetime'],
        'array'  => ['json'],
        'float'  => ['float', 'double', 'decimal',],
        'bool'   => ['boolean',],
    ];


    /**
     * @return void
     */
    protected function configure(): void
    {
        $this->setName('sw:controller')
             ->addOption('database', null, InputOption::VALUE_REQUIRED, 'is run daemonize')
             ->addOption('table', null, InputOption::VALUE_OPTIONAL, 'is run daemonize')
             ->addOption('all-table', null, InputOption::VALUE_NONE, 'is run daemonize');

    }


    /**
     * @param InputInterface $input
     * @param OutputInterface $output
     * @return int
     */
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $daemon = (int)$input->getOption('all-table');

        $database = \Kiri::getDi()->get(DatabasesProviders::class)->get($input->getOption('database'));

        $namespace = $input->getOption('database');
        if ($daemon) {
            $tables = Db::connect($database)->fetchAll('show tables');
            foreach ($tables as $table) {
                $this->putFile(Db::desc(current($table), $database), $namespace, $database, current($table));
            }
        } else {
            $this->putFile(Db::desc($input->getOption('table'), $database), $namespace, $database, $input->getOption('table'));
        }
        return 0;
    }


    /**
     * @param array $data
     * @param string $namespace
     * @param Connection $database
     * @param string $table
     * @return void
     */
    protected function putFile(array $data, string $namespace, Connection $database, string $table): void
    {
        $fieldMaxLength = $this->maxLength($data);
        $where          = [];
        foreach ($data as $datum) {
            $where[] = '
        $where[\'' . $datum['Field'] . '\'] ' . str_pad('', $fieldMaxLength - mb_strlen($datum['Field']), ' ') . '= $this->request->query(\'' . $datum['Field'] . '\', NULL);';
        }

        $dbName = $this->clearXiaHuaXian($namespace);

        $table = str_replace($database->tablePrefix, '', $table);
        if (str_contains($table, '-')) {
            $table = str_replace('-', '_', $table);
        }
        $class = $this->clearXiaHuaXian($table, '');

        $prefix = $dbName == 'Db' ? '' : '\\' . ucfirst($dbName);

        $name      = 'App\Controller' . $prefix . '\\' . $class . 'Controller';
        $imports   = ['use App\Model' . $prefix . '\\' . $class . ';'];
        $imports[] = 'use App\Controller\Controller;';
        $imports[] = 'use Kiri\Router\Validator\BindForm;';
        $imports[] = 'use Psr\Http\Message\ResponseInterface;';
        $imports[] = 'use Exception;';
        $imports[] = 'use App\Form' . $prefix . '\\' . $class . 'Form;';

        $properties = [];
        $names      = [];
        $traits     = [];
        if (class_exists($name)) {
            var_dump($name);
            $reflation = new \ReflectionClass($name);
            var_dump($reflation);
            [$imports, $traits] = $this->getTraits($reflation, $imports);

            [$imports, $oldMethods] = $this->getOldMethods($reflation, $imports);

            $array = [];
            foreach ($reflation->getMethods() as $method) {
                if ($method->getDeclaringClass()->getName() != $reflation->getName()) {
                    continue;
                }
                $array[] = $method->getName();
            }
            if (!in_array('actionAdd', $array)) {
                $oldMethods[] = $this->defaultAdd($class, $fieldMaxLength, $where);
            }
            if (!in_array('actionUpdate', $array)) {
                $oldMethods[] = $this->defaultUpdate($class, $fieldMaxLength, $where);
            }
            if (!in_array('actionDetail', $array)) {
                $oldMethods[] = $this->defaultDetail($class, $fieldMaxLength, $where);
            }
            if (!in_array('actionDelete', $array)) {
                $oldMethods[] = $this->defaultDelete($class, $fieldMaxLength, $where);
            }
            if (!in_array('actionBatchDelete', $array)) {
                $oldMethods[] = $this->actionBatchDelete($class, $fieldMaxLength, $where);
            }
            if (!in_array('actionAuditing', $array)) {
                $oldMethods[] = $this->actionAuditing($class, $fieldMaxLength, $where);
            }
            if (!in_array('actionBatchAuditing', $array)) {
                $oldMethods[] = $this->actionBatchAuditing($class, $fieldMaxLength, $where);
            }
            if (!in_array('actionList', $array)) {
                $oldMethods[] = $this->actionList($class, $fieldMaxLength, $where);
            }
            [$imports, $properties] = $this->resetProperty($reflation, $imports);

            [$imports, $names] = $this->getInterfaces($reflation, $imports);
        } else {
            $oldMethods = $this->defaultMethod($class, $fieldMaxLength, $where);
        }
        $html = '<?php
declare(strict_types=1);

namespace App\Controller' . $prefix . ';

' . implode(PHP_EOL, $imports) . '


/**
 * Class ' . $class . 'Controller
 *
 * @package controller
 */
class ' . $class . 'Controller extends Controller' . (empty($names) ? '' : ' implements ' . implode(',', $names)) . '
{' . implode(PHP_EOL, $traits) . implode(PHP_EOL, $properties) . '

' . implode(PHP_EOL . PHP_EOL, $oldMethods) . '
}';

        $dir = APP_PATH . 'app/Controller';
        if ($namespace != 'db') {
            $dir = APP_PATH . 'app/Controller/' . ucfirst($dbName);
        }
        if (!is_dir($dir)) {
            mkdir($dir, 0777, true);
        }
        file_put_contents($dir . '/' . $class . 'Controller.php', $html);
    }


    protected function defaultAdd($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @param ' . $class . 'Form $form
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionAdd(#[BindForm(' . $class . 'Form::class)] ' . $class . 'Form $form): ResponseInterface
    {
        $model = ' . $class . '::populate($form->toArray());
        if (!$model->save()) {
            return $this->response->json([\'code\' => 500, \'message\' => $model->getLastError()]);
        } else {
            return $this->response->json([\'code\' => 0, \'param\' => $model->toArray()]);
        }
    }';
    }


    protected function defaultUpdate($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @param ' . $class . 'Form $form
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionUpdate(#[BindForm(' . $class . 'Form::class)] ' . $class . 'Form $form): ResponseInterface
    {
        $model             = ' . $class . '::findOne($this->request->post(\'id\', 0));
        $model->attributes = $form->toArray();
        if (!$model->save()) {
            return $this->response->json([\'code\' => 500, \'message\' => $model->getLastError()]);
        } else {
            return $this->response->json([\'code\' => 0, \'param\' => $model->toArray()]);
        }
    }';
    }


    protected function defaultDetail($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionDetail(): ResponseInterface
    {
        $model = ' . $class . '::findOne($this->request->query(\'id\', 0));
        if (!empty($model)) {
            return $this->response->json([\'code\' => 0, \'param\' => $model->toArray()]);
        } else {
            return $this->response->json([\'code\' => 500, \'message\' => SELECT_IS_NULL]);
        }
    }';
    }


    protected function defaultDelete($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionDelete(): ResponseInterface
    {
        $primaryKey = $this->request->post(\'id\', 0);
        $model      = ' . $class . '::query()->where([\'id\' => $primaryKey])->delete();
        if ($model === false) {
            return $this->response->json([\'code\' => 500, \'message\' => \'删除失败, 请重试\']);
        } else {
            return $this->response->json([\'code\' => 0, \'message\' => \'ok\']);
        }
    }';
    }


    protected function actionBatchDelete($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionBatchDelete(): ResponseInterface
    {
        $model = ' . $class . '::query()->whereIn(\'id\', $this->request->post(\'ids\', []));
        if ($model->delete() === false) {
            return $this->response->json([\'code\' => 500, \'message\' => \'删除失败, 请重试\']);
        } else {
            return $this->response->json([\'code\' => 0, \'message\' => \'ok\']);
        }
    }';
    }


    protected function actionAuditing($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionAuditing(): ResponseInterface
    {
        $model = ' . $class . '::findOne($this->request->post(\'id\', 0));
        if (empty($model)) {
            return $this->response->json([\'code\' => 500, \'message\' => \'必填项不能为空\']);
        }
        if (!$model->update([\'state\' => (int)$this->request->post(\'state\')])) {
            return $this->response->json([\'code\' => 500, \'message\' => $model->getLastError()]);
        } else {
            return $this->response->json([\'code\' => 0, \'data\' => $model->toArray()]);
        }
    }';
    }


    protected function actionBatchAuditing($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionBatchAuditing(): ResponseInterface
    {
        $ids = $this->request->post(\'ids\', []);
        if (empty($ids)) {
            return $this->response->json([\'code\' => 500, \'message\' => \'必填项不能为空\']);
        }
        if (!' . $class . '::query()->whereIn(\'id\', $ids)->update([\'state\' => (int)$this->request->post(\'state\')])) {
            return $this->response->json([\'code\' => 500, \'message\' => \'系统繁忙, 请稍后再试\']);
        } else {
            return $this->response->json([\'code\' => 0, \'message\' => \'ok\']);
        }
    }';
    }


    protected function actionList($class, $fieldMaxLength, $where): string
    {
        return '
    /**
     * @return ResponseInterface
     * @throws Exception
     */
    public function actionList(): ResponseInterface
    {
        $where ' . str_pad('', $fieldMaxLength + 4, ' ') . '= [];' . implode($where) . '

        $data = ' . $class . '::query()->where($where);
        if ($this->request->has(\'keyword\')) {
            $data->whereLike(\'keyword\', $this->request->query(\'keyword\'));
        }
        $dataCount = $data->count();
        $sortType  = $this->request->queryInt(\'isDesc\', 0) == 1 ? \'DESC\' : \'ASC\';
        $sortField = $this->request->query(\'order\', \'id\');
        $pageSize  = $this->request->queryInt(\'size\', 20);
        $page      = $this->request->query(\'page\', 1);
        if ($page < 1) {
            $page = 1;
        }
        $pageOffset = ceil(($page - 1) * $pageSize);

        $member = $data->orderBy($sortField, $sortType)->offset((int)$pageOffset)->limit($pageSize)->get()->toArray();

        return $this->response->json([\'code\' => 0, \'param\' => $member, \'count\' => $dataCount]);
    }';
    }


    /**
     * @param $class
     * @param $fieldMaxLength
     * @param $where
     * @return string[]
     */
    protected function defaultMethod($class, $fieldMaxLength, $where): array
    {
        return [
            $this->defaultAdd($class, $fieldMaxLength, $where),
            $this->defaultUpdate($class, $fieldMaxLength, $where),
            $this->defaultDetail($class, $fieldMaxLength, $where),
            $this->defaultDelete($class, $fieldMaxLength, $where),
            $this->actionBatchDelete($class, $fieldMaxLength, $where),
            $this->actionAuditing($class, $fieldMaxLength, $where),
            $this->actionBatchAuditing($class, $fieldMaxLength, $where),
            $this->actionList($class, $fieldMaxLength, $where),
        ];
    }
}